package com.zsc.shixun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zsc.shixun.common.ResultCode;
import com.zsc.shixun.contant.Contant;
import com.zsc.shixun.entity.User;
import com.zsc.shixun.exception.ApiException;
import com.zsc.shixun.mapper.UserMapper;
import com.zsc.shixun.model.unauthorize.AuthorityVO;
import com.zsc.shixun.model.unauthorize.UserRegisterVO;
import com.zsc.shixun.model.usermanage.UserMapping;
import com.zsc.shixun.model.user.UserUpdateVO;
import com.zsc.shixun.model.user.UserVO;
import com.zsc.shixun.model.usermanage.UserManageCreateVO;
import com.zsc.shixun.model.usermanage.UserManageUpdateVO;
import com.zsc.shixun.model.usermanage.UserManageVO;
import com.zsc.shixun.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.shixun.utils.FIleUtils;
import com.zsc.shixun.utils.LoginMessageUtils;
import com.zsc.shixun.utils.ProducerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author ZWYZY
 * @since 2020-06-06
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private ProducerUtils producerUtils;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    public UserMapper userMapper;

    @Resource
    public UserDetailsService userDetailsService;
    @Resource
    public FIleUtils fIleUtils;
    @Resource
    public LoginMessageUtils loginMessageUtils;

    @Autowired
    private UserMapping userMapping;

    @Override
    public String register(UserRegisterVO userRegisterVO) {
        System.out.println(userRegisterVO);
        if (this.getOne(new QueryWrapper<User>().eq("username", userRegisterVO.getUsername())) != null) {
            throw new ApiException(ResultCode.USERNAME_HAS_EXIST);
        }
        if (this.getOne(new QueryWrapper<User>().eq("email", userRegisterVO.getEmail())) != null) {
            logger.info("数据库已有该邮箱" + userRegisterVO.getEmail());
            throw new ApiException(ResultCode.USER_HAS_EXIST);
        }
        User user = new User();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        userRegisterVO.setPassword(bCryptPasswordEncoder.encode(userRegisterVO.getPassword()));
        BeanUtils.copyProperties(userRegisterVO, user);
        this.save(user);
        logger.info("该邮箱注册成功：" + userRegisterVO.getEmail());
        producerUtils.sendNotice(user.getEmail(), "it技术博客管理系统", user.getUsername() + "同学：感谢注册我们的博客，爱你哦！！！");
        return "注册成功";
    }

    @Override
    public User getUser(String s) {
        User user = null;
        Object o = redisTemplate.opsForValue().get(Contant.MESSAGE_KEY + s);
        if (o != null) {
            user = (User) o;
        } else {
            user = this.getOne(new QueryWrapper<User>().eq("email", s));

            if (user != null) {
                redisTemplate.opsForValue().set(Contant.MESSAGE_KEY + s, user);
            }
        }
        return user;
    }


    @Override
    public List<String> getUserAuthority(String s) {
        List<String> list = new ArrayList<>(10);
        Object o = redisTemplate.opsForValue().get(Contant.AUTHORITY_KEY + s);
        if (o != null) {
            list = (List<String>) o;
        } else {
            List<AuthorityVO> authorities = userMapper.getAuthority(s);

            for (AuthorityVO a : authorities
            ) {
                if (a.crudauth.length() != 0) {
                    list.addAll(Arrays.asList(a.getCrudauth().split(",")));
                }
            }
            if (authorities.size() > 0) {
                redisTemplate.opsForValue().set(Contant.AUTHORITY_KEY + s, list);
            }
        }
        return list;
    }


    @Override
    public User findByEmail(String email) {
        User user = this.getOne(new QueryWrapper<User>().eq("email", email));

        return user;
    }

    @Override
    public User findByUsername(String username) {
        User user = this.getOne(new QueryWrapper<User>().eq("username", username));
        if (user == null) {
            throw new ApiException(ResultCode.USER_NOT_FOUND);
        }
        return user;
    }

    @Override
    public UserVO findById(Long id) {
        if (redisTemplate.hasKey(Contant.USER_KEY + id)) {
            return (UserVO) redisTemplate.opsForValue().get(Contant.USER_KEY + id);
        }
        UserVO userVO = new UserVO();
        User user = this.getById(id);
        BeanUtils.copyProperties(user, userVO);
        redisTemplate.opsForValue().set(Contant.USER_KEY + id, userVO);
        return userVO;
    }

    @Override
    public void updateByImg(Long id, String fullPath) {
        User searchUser = this.getById(id);
        fIleUtils.deleteFile(searchUser.getImg());
        User user = new User();
        user.setId(id);
        user.setImg(fullPath);
        try {
            this.updateById(user);
        } catch (Exception e) {
            logger.error("修改图片失败");
            throw new ApiException(ResultCode.USER_UPDATE_FAIL);
        }
        logger.info("id为：" + id + "修改头像成功");
        if (redisTemplate.hasKey(Contant.USER_KEY + id)) {
            redisTemplate.delete(Contant.USER_KEY + id);
        }
        updateUserCache(id);
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }

    }

    @Override
    public void updateUser(UserUpdateVO userUpdateVO, String rawUserName) {
        if (!rawUserName.equals(userUpdateVO.getUsername())) {
            User user = this.getOne(new QueryWrapper<User>().lambda().eq(User::getUsername, userUpdateVO.getUsername()));
            if (user != null) {
                throw new ApiException(ResultCode.USERNAME_HAS_EXIST);
            }
        }
        User user = new User();
        BeanUtils.copyProperties(userUpdateVO, user);

        try {
            this.updateById(user);
        } catch (Exception e) {
            logger.error("插入个人资料失败");
            throw new ApiException(ResultCode.USER_UPDATE_FAIL);
        }
        logger.info("id为：" + userUpdateVO.getId() + "修改资料成功");
        if (redisTemplate.hasKey(Contant.USER_KEY + userUpdateVO.getId())) {
            redisTemplate.delete(Contant.USER_KEY + userUpdateVO.getId());
        }
        updateUserCache(userUpdateVO.getId());
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }

    }


    @Override
    public void updatePassword(String password, Long uid) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        User user = new User();
        user.setId(uid);
        user.setPassword(bCryptPasswordEncoder.encode(password));
        try {
            this.updateById(user);
        } catch (Exception e) {
            logger.error("修改密码失败");
            throw new ApiException(ResultCode.USER_UPDATE_FAIL);
        }
        logger.info("id为：" + uid + "更改密码成功");
        if (redisTemplate.hasKey(Contant.USER_KEY + uid)) {
            redisTemplate.delete(Contant.USER_KEY + uid);
        }
        updateUserCache(uid);
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }

    }

    /**
     * 更改缓存
     *
     * @param uid
     */
    @Override
    public void updateUserCache(Long uid) {
        User currentUser = this.getById(uid);
        if (redisTemplate.hasKey(Contant.MESSAGE_KEY + currentUser.getEmail())) {
            redisTemplate.opsForValue().set(Contant.MESSAGE_KEY + currentUser.getEmail(), currentUser);
            logger.info("更新user缓存成功");
            updateAuthorityCache(currentUser.getEmail());
            logger.info("更新权限缓存成功");
            if (!"-1".equals(loginMessageUtils.isLogin().toString())&&uid.equals(loginMessageUtils.getMessage().getLoginUser().getId())) {
                loginMessageUtils.setMessage(userDetailsService.loadUserByUsername(currentUser.getEmail()));
                logger.info("更新登录信息成功");

            }
        }
    }

    /**
     * 更新权限缓存
     *
     * @param s
     */
    public void updateAuthorityCache(String s) {
        List<String> list = new ArrayList<>(10);
        List<AuthorityVO> authorities = userMapper.getAuthority(s);
        authorities.forEach(a->{
            if (a.getCrudauth().length() != 0) {
                list.addAll(Arrays.asList(a.getCrudauth().split(",")));
            }
        });
//        for (AuthorityVO a : authorities
//        ) {
//            if (a.getCrudauth().length() != 0) {
//                list.addAll(Arrays.asList(a.getCrudauth().split(",")));
//            }
//        }
        if (authorities.size() > 0) {
            redisTemplate.opsForValue().set(Contant.AUTHORITY_KEY + s, list);
        }
    }

    @Override
    public List<UserManageVO> getById() {
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            return (List<UserManageVO>) redisTemplate.opsForValue().get(Contant.USER_MANAGE_KEY);
        }
        List<User> userList = this.list();
        List<UserManageVO> userManageVOS = userMapping.entitysToVos(userList);

        redisTemplate.opsForValue().set(Contant.USER_MANAGE_KEY, userManageVOS);
        return userManageVOS;
    }

    @Override
    public void update(UserManageUpdateVO userManageUpdateVO) {
        User user = new User();
        BeanUtils.copyProperties(userManageUpdateVO, user);
        try {
            this.updateById(user);
        } catch (Exception e) {
            logger.error("修改用户失败");
            throw new ApiException(ResultCode.USER_MANAGE_UPDATE_FAIL);
        }
        logger.info("修改用户成功");
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }
        updateUserCache(user.getId());
        if (redisTemplate.hasKey(Contant.USER_KEY + user.getId())) {
            redisTemplate.delete(Contant.USER_KEY + user.getId());
        }
    }

    @Override
    public void delete(Long id) {
        try {
            updateUserCache(id);
            this.removeById(id);
        } catch (Exception e) {
            logger.error("用户删除失败");
            throw new ApiException(ResultCode.USER_MANAGE_DELETE_FAIL);
        }
        logger.info("删除用户成功");
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }
        if (redisTemplate.hasKey(Contant.USER_KEY + id)) {
            redisTemplate.delete(Contant.USER_KEY + id);
        }

    }

    @Override
    public void insert(UserManageCreateVO userManageCreateVO) {
        if (this.getOne(new QueryWrapper<User>().eq("username", userManageCreateVO.getUsername())) != null) {
            throw new ApiException(ResultCode.USERNAME_HAS_EXIST);
        }
        if (this.getOne(new QueryWrapper<User>().eq("email", userManageCreateVO.getEmail())) != null) {
            logger.info("数据库已有该邮箱" + userManageCreateVO.getEmail());
            throw new ApiException(ResultCode.USER_HAS_EXIST);
        }
        User user = new User();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        userManageCreateVO.setPassword(bCryptPasswordEncoder.encode(userManageCreateVO.getPassword()));
        BeanUtils.copyProperties(userManageCreateVO, user);
        try {
            this.save(user);
        } catch (Exception e) {
            logger.error("创建管理员失败");
            throw new ApiException(ResultCode.USER_MANAGE_INSERT_FAIL);
        }
        logger.info("创建管理员成功");
        if (redisTemplate.hasKey(Contant.USER_MANAGE_KEY)) {
            redisTemplate.delete(Contant.USER_MANAGE_KEY);
        }
    }

}
